package br.com.napoleao.controlfin.core.persistence.dao;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;

import br.com.napoleao.controlfin.core.entity.CategoriaEntity;
import br.com.napoleao.controlfin.core.entity.ContaEntity;
import br.com.napoleao.controlfin.core.entity.MovimentacaoEntity;
import br.com.napoleao.controlfin.core.entity.PessoaEntity;
import br.com.napoleao.controlfin.core.entity.dto.FaixaValorDTO;
import br.com.napoleao.controlfin.core.entity.dto.PeriodoDTO;
import br.com.napoleao.controlfin.core.enums.TipoMovimentacao;
import br.com.napoleao.controlfin.core.persistence.factory.EntityManagerProvider;

public class MovimentacaoDAO extends CrudDAO<MovimentacaoEntity>{

	private EntityManager em;
	
	public List<MovimentacaoEntity> buscarFiltradoControle(List<TipoMovimentacao> filtroTpMov, List<ContaEntity> filtroConta, List<CategoriaEntity> filtroCat,
			List<PessoaEntity> filtroPessoa, PeriodoDTO dataMov, FaixaValorDTO valorMov, PeriodoDTO dataPrevMov, FaixaValorDTO valorPrevMov){
	
		List<String> filtroMov = new ArrayList<String>();
		
		if(filtroTpMov != null)
			for (TipoMovimentacao mov : filtroTpMov) {
				filtroMov.add(mov.getValue());
			}
		
		StringBuffer hql = new StringBuffer();
			hql.append("from MovimentacaoEntity ");
			hql.append("where 1=1 ");
			if(filtroCat != null && filtroCat.size() > 0) hql.append("and categoria in( :listCat ) ");
			if(filtroConta != null && filtroConta.size() > 0) hql.append(" and conta in ( :listConta ) ");
			if(filtroPessoa != null && filtroPessoa.size() > 0) hql.append(" and pessoa in ( :listPessoa ) ");
			if(filtroMov != null && filtroMov.size() > 0) hql.append(" and tipoMovimentacao in ( :listMov ) ");
			if(dataMov != null && (dataMov.getDataInicial() != null || dataMov.getDataFinal() != null)){
				hql.append(" and (");
				boolean usaAnd = false;
				if(dataMov.getDataInicial() != null){
							hql.append("dataMov >= :dtMovInicial ");
							usaAnd = true;
						}
						if(dataMov.getDataFinal() != null){
							if(usaAnd) hql.append("and ");
							hql.append("dataMov <= :dtMovFinal ");
						}
						hql.append(" or dataMov is null ");
			hql.append(") ");
			}
			if(dataPrevMov != null && (dataPrevMov.getDataInicial() != null || dataPrevMov.getDataFinal() != null)){
				hql.append(" and (");
				boolean usaAnd = false;
				if(dataPrevMov.getDataInicial() != null){
					hql.append("dataPrevistaMov >= :dtPrevInicial ");
					usaAnd = true;
				}
				if(dataPrevMov.getDataFinal() != null){
					if(usaAnd) hql.append("and ");
					hql.append("dataPrevistaMov <= :dtPrevFinal ");
				}
				hql.append(" or dataPrevistaMov is null ");
				hql.append(") ");
			}
			
			if(valorMov != null && ((valorMov.getValorInicial() != null && valorMov.getValorInicial() != 0.0) || 
					(valorMov.getValorFinal() != null && valorMov.getValorFinal() != 0.0))){
				hql.append(" and (");
				boolean usaAnd = false;
				if(valorMov.getValorInicial() != null && valorMov.getValorInicial() != 0.0){
							hql.append("valorMov >= :vlInicial ");
							usaAnd = true;
						}
						if(valorMov.getValorFinal() != null && valorMov.getValorFinal() != 0.0){
							if(usaAnd) hql.append("and ");
							hql.append("valorMov <= :vlFinal ");
						}
						hql.append(" or valorMov = 0.0 ");
						hql.append(" or valorMov = null ");
						hql.append(") ");
			}
			if(valorPrevMov != null && ((valorPrevMov.getValorInicial()!= null && valorPrevMov.getValorInicial() != 0.0) || 
					(valorPrevMov.getValorFinal() != null && valorPrevMov.getValorFinal() != 0.0))){
				hql.append(" and (");
				boolean usaAnd = false;
				if(valorPrevMov.getValorInicial() != null && valorPrevMov.getValorInicial() != 0.0){
					hql.append("valorPrevistaMov >= :vlPrevInicial ");
					usaAnd = true;
				}
				if(valorPrevMov.getValorFinal() != null && valorPrevMov.getValorFinal() != 0.0){
					if(usaAnd) hql.append("and ");
					hql.append("valorPrevistaMov <= :vlPrevFinal ");
				}
				hql.append(" or valorPrevistaMov = 0.0 ");
				hql.append(" or valorPrevistaMov = null ");
				hql.append(") ");
			}
			
		EntityManagerFactory emf = EntityManagerProvider.getEntityManagerFactory();
		em = emf.createEntityManager();
	
		em.getTransaction().begin();
		
		Query query = em.createQuery(hql.toString());
		if(filtroCat != null && filtroCat.size() > 0) query.setParameter("listCat", filtroCat);
		if(filtroConta != null && filtroConta.size() > 0) query.setParameter("listConta", filtroConta);
		if(filtroPessoa != null && filtroPessoa.size() > 0) query.setParameter("listPessoa", filtroPessoa);
		if(filtroMov != null && filtroMov.size() > 0) query.setParameter("listMov", filtroMov);
		if(dataMov != null && dataMov.getDataInicial() != null) query.setParameter("dtMovInicial", dataMov.getDataInicial());
		if(dataMov != null && dataMov.getDataFinal() != null) query.setParameter("dtMovFinal", dataMov.getDataFinal());
		if(dataPrevMov != null && dataPrevMov.getDataInicial() != null) query.setParameter("dtPrevInicial", dataPrevMov.getDataInicial());
		if(dataPrevMov != null && dataPrevMov.getDataFinal() != null) query.setParameter("dtPrevFinal", dataPrevMov.getDataFinal());
		if(valorMov != null && valorMov.getValorInicial() != null && valorMov.getValorInicial() != 0.0) query.setParameter("vlInicial", valorMov.getValorInicial());
		if(valorMov != null && valorMov.getValorFinal() != null && valorMov.getValorFinal() != 0.0) query.setParameter("vlFinal", valorMov.getValorFinal());
		if(valorPrevMov != null && valorPrevMov.getValorInicial() != null && valorPrevMov.getValorInicial() != 0.0) query.setParameter("vlPrevInicial", valorPrevMov.getValorInicial());
		if(valorPrevMov != null && valorPrevMov.getValorFinal() != null && valorPrevMov.getValorFinal() != 0.00) query.setParameter("vlPrevFinal", valorPrevMov.getValorFinal());
		
		List<MovimentacaoEntity> resultado = query.getResultList();
		
		em.getTransaction().commit();

		return resultado;
	}
			
	
}
